#ifndef _DRIVER_PWM_H
#define _DRIVER_PWM_H

#include "plf.h"
#include <stdbool.h>

enum pwm_channel_t {
    PWM_CHANNEL_0,
    PWM_CHANNEL_1,
    PWM_CHANNEL_2,
    PWM_CHANNEL_3,
    PWM_CHANNEL_4,
    PWM_CHANNEL_5,
    PWM_CHANNEL_6,
    PWM_CHANNEL_7,
    PWM_CHANNEL_DAC_MAX,
    PWM_CHANNEL_8 = PWM_CHANNEL_DAC_MAX,
    PWM_CHANNEL_9,
    PWM_CHANNEL_10,
    PWM_CHANNEL_11,
    PWM_CHANNEL_MAX,
};


enum pwm_channel_num_t {
    PWM_CHANNEL_NUM0=0x01,
    PWM_CHANNEL_NUM1=0x02,
    PWM_CHANNEL_NUM2=0x04,
    PWM_CHANNEL_NUM3=0x08,
    PWM_CHANNEL_NUM4=0x10,
    PWM_CHANNEL_NUM5=0x20,
    PWM_CHANNEL_NUM6=0x40,
    PWM_CHANNEL_NUM7=0x80,

};

enum pwm_mode_t {
    PWM_NORMAL_MODE,
    PWM_DAC_LEVELOUT_MODE,
};

#define PTC0_RPTC_CNTR          (PWM_BASE+0x00)
#define PWM_ENABLE              (PWM_BASE+0x08)
#define PWM_POSEDGE0            (PWM_BASE+0x10)
#define PWM_NEGEDGE0            (PWM_BASE+0x14)
#define PWM_STRETCH             (PWM_BASE+0x90)
#define PWM_TACH_PRESCALE       (PWM_BASE+0x94)
#define PWM_TACH_STATUS         (PWM_BASE+0x98)
#define PWM_TACH_IRQMASK        (PWM_BASE+0x9c)
#define PWM_TACH_MODE           (PWM_BASE+0xa0)
#define PWM_TACH_PULSE_DUR0     (PWM_BASE+0xa4)
#define PWM_SYNC_UPDATE         (PWM_BASE+0xe4)
#define PWM_DAC_MODE            (PWM_BASE+0xe8)
#define PWM_SHADOW_REG_EN       (PWM_BASE+0xec)
#define PWM_STRETCH_VALUE       (PWM_BASE+0xf0)
#define PWM_OUTPUT_INV          (PWM_BASE+0xf8)
#define PWM_CNT_ENABLE          (PWM_BASE+0xfc)
#define PWM_PRESCALE0           (PWM_BASE+0x100)
#define PWM_PERIOD0             (PWM_BASE+0x104)
#define PWM_DAC_PCLK_DIV0       (PWM_BASE+0x140)

struct pwm_edge_t{
    uint32_t pos_edge;
    union {
        uint32_t neg_edge;
        uint32_t dac_levelout;
    }p;
};

struct pwm_output_en{
    uint32_t en:8;
    uint32_t resv:24;
};
struct pwm_enable_t{
    uint32_t en:8;
    uint32_t resv:24;
};
struct pwm_stretch_t{
    uint32_t en:12;
    uint32_t resv:20;
};
struct pwm_tach_prescale_t{
    uint32_t prescale:4;
    uint32_t int_act_lvl:4;
    uint32_t resv:24;
};

struct pwm_tach_status_t{
    uint32_t status:8;
    uint32_t resv:24;
};

struct pwm_tach_irqmask_t{
    uint32_t mask:8;
    uint32_t resv:24;
};

struct pwm_tach_mode_t{
    uint32_t mode:8;
    uint32_t en:8;
    uint32_t resv:16;
};

struct pwm_sync_update_t{
    uint32_t update:12;
    uint32_t resv0:4;
    uint32_t normal_status:12;
    uint32_t resv1:4;
};

struct pwm_mod_t{
    uint32_t mode:8;    //0--noraml,1---low ripple DAC mode
    uint32_t resv:24;
};

struct pwm_shadow_reg_en_t{
    uint32_t shadow_en:8;
    uint32_t resv:24;
};
struct pwm_stretch_val_t{
    uint32_t val:12;
    uint32_t resv:20;
};
struct pwm_output_inv_t{
    uint32_t inv:12;
    uint32_t resv:20;
};
struct pwm_cnt_en_t{
    uint32_t cnt_en:12;
    uint32_t resv:20;
};

struct pwm_config_t{
    uint32_t prescale;
    uint32_t period;
};

struct pwm_dac_div_cnt_t{
    uint32_t cnt:16;
    uint32_t resv:16;
};


struct pwm_reg_t{
    uint32_t resv[1];               //0x00
    struct pwm_output_en out_enable;
    struct pwm_enable_t enable;                //0x08
    uint32_t resv1;                 //0x0c
    struct pwm_edge_t edge[PWM_CHANNEL_MAX];//0x10 ~0x6c
    uint32_t resv2[8];             //0x70
    struct pwm_stretch_t stretch;               //0x90
    struct pwm_tach_prescale_t tach;         //0x94
    struct pwm_tach_status_t tach_status;       //0x98
    struct pwm_tach_irqmask_t tach_irq_mask;         //0x9c
    struct pwm_tach_mode_t tach_mode;           //0xa0
    uint32_t tach_pulse_dur[PWM_CHANNEL_DAC_MAX];   //0xa4~0xc0
    uint32_t resv3[8];                           //0xc4
    struct pwm_sync_update_t sync_update;       //0xe4
    struct pwm_mod_t mode;                   //0xe8
    struct pwm_shadow_reg_en_t shadow;          //0xec
    struct pwm_stretch_val_t stretch_val;    //0xf0
    uint32_t resv4;                          //0xf4
    struct pwm_output_inv_t inv;             //0xf8
    struct pwm_cnt_en_t cnt_en;              //0xfc
    struct pwm_config_t config[PWM_CHANNEL_MAX];    //0x100
    uint32_t resv5[8];                        //0x160
    struct pwm_dac_div_cnt_t dac_div_cnt[PWM_CHANNEL_DAC_MAX];         //0x180
    
};

/*********************************************************************
 * @fn      pwm_init
 *
 * @brief   init one pwm channel.
 *
 * @param   channel           - pwm channel, @ref pwm_channel_t.
 *          mode              - pwm mode, @ pwm_mode_t
 *          scale             - pwm clock divide factor
 *          period            - the number of pwm clk
 *          pos_start_offset  - start position of rise edge
 *          pos_dur           - end position of rise edge
 *
 * @return  None.
 */
void pwm_init(enum pwm_channel_t channel, enum pwm_mode_t mode, uint32_t scale, uint32_t period,uint32_t pos_start_offset, uint32_t pos_dur);

/*********************************************************************
 * @fn      pwm_start
 *
 * @brief   start one pwm channel.
 *
 * @param   channel     - pwm channel, @ref pwm_channel_num_t.
 *
 * @return  None.
 */
 void pwm_start(enum pwm_channel_num_t channel);

/*********************************************************************
 * @fn      pwm_stop
 *
 * @brief   stop one working pwm channel.
 *
 * @param   channel     - pwm channel, @ref pwm_channel_t.
 *
 * @return  None.
 */
void pwm_stop(enum pwm_channel_t channel);

/*********************************************************************
 * @fn      pwm_enable_inverter
 *
 * @brief   enable pwm channel pwm waveform inverter
 *
 * @param   channel  - pwm channel, @ref pwm_channel_num_t.
 *
 * @return  None.
 */
void pwm_enable_inverter(enum pwm_channel_num_t channel);


/*********************************************************************
 * @fn     pwm_dynamic_update
 *
 * @brief    not stop pwm,modify parameter and restart pwm
 *
 * @param   channel           - pwm channel, @ref pwm_channel_t.
 *          mode              - pwm mode, @ pwm_mode_t
 *          scale             - pwm clock divide factor
 *          period            - the number of pwm clk
 *          pos_start_offset  - start position of rise edge
 *          pos_dur           - end position of rise edge
 *
 * @return  None.
 */
void pwm_dynamic_update(enum pwm_channel_t channel, enum pwm_mode_t mode, uint32_t scale, 
uint32_t period,uint32_t pos_start_offset, uint32_t pos_dur);


/*********************************************************************
 * @fn      pwm_dynamic_update_start
 *
 * @brief   restart one pwm channel.
 *
 * @param   channel     - pwm channel, @ref pwm_channel_num_t.
 *
 * @return  None.
 */
void pwm_dynamic_update_start(enum pwm_channel_num_t channel);

void pwm_tach_init(enum pwm_channel_num_t channel,uint8_t scale,bool continue_flag);
uint8_t pwm_read_tach_status();
uint32_t pwm_read_tach_value(enum pwm_channel_t channel);
void clear_pwm_status();
void pwm_test();



#endif